﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DcsGauges.Gui.Gauges.Interfaces;
using DcsGauges.Shared.DataStructures;
using DcsGauges.Gui.Rendering;
using Microsoft.Xna.Framework.Graphics;
using DcsGauges.DataStructures;
using Microsoft.Xna.Framework;
using DcsGauges.Input.Events;
using DcsGauges.Input.Processors;
using DcsGauges.Gui.Gauges.ValueConverters;
using System.Diagnostics;

namespace DcsGauges.Gui.Gauges.Trigger
{
    class TwoStateToggleSwitchGauge : GuiRenderableBase, ITriggerGauge
    {
        #region InnerTypes

        public enum SwitchStates
        {
            State0,
            State1,
        }

        public enum Orientation
        {
            Vertical,
            Horizontal,
        }

        #endregion


        #region Event Handlers

        public event EventHandler<TriggerValueEventArgs>        TriggerEvent                        = delegate { };

        #endregion


        #region Fields / Properties
        
        private Texture2D                                       state0Texture                       = null;
        private Texture2D                                       state1Texture                       = null;
        private StateConverter<SwitchStates>                    converter                           = null;
        private SwipeProcessor                                  inputProcessor                      = null;
        private Orientation                                     orientation                         = Orientation.Vertical;
        private SwipeProcessor.SwipeEventArgs.SwipeDirections   nextStateDirection                  = SwipeProcessor.SwipeEventArgs.SwipeDirections.Negative;

        #endregion


        #region Constructors

        public TwoStateToggleSwitchGauge(GuiRenderableBase parent, URect area, DcsProperty property,
            Texture2D state0Texture, Texture2D state1Texture,
            StateConverter<SwitchStates> converter, Orientation orientation = Orientation.Vertical) : base(parent, area)
        {
            this.state0Texture              = state0Texture;
            this.state1Texture              = state1Texture;
            this.converter                  = converter;
            this.DataProperty               = property;
            this.orientation                = orientation;

            if (this.orientation == Orientation.Vertical)
            {
                this.inputProcessor             = new VerticalSwipeProcessor(this);
                this.nextStateDirection         = SwipeProcessor.SwipeEventArgs.SwipeDirections.Negative;
            }
            else
            {
                this.inputProcessor             = new HorizontalSwipeProcessor(this);
                this.nextStateDirection         = SwipeProcessor.SwipeEventArgs.SwipeDirections.Positive;
            }

            this.inputProcessor.SwipeEvent  +=  HandleInputProcessorSwipeEvent;
        }

        #endregion


        #region Interface Implementation

        #region Fields / Properties

        public DcsProperty DataProperty
        {
            get; private set;
        }

        
        public float Value
        {
            get; set;
        }

        #endregion

        #endregion


        #region Overrides

        public override void Render(SpriteBatch spriteBatch, GraphicsDevice device, Rectangle parentRect, float globalZIndex)
        {
            SwitchStates switchState            = this.converter.Convert(this.Value);
            if (switchState == SwitchStates.State0)
            {
                Rectangle switchRect            = this.CalcViewportRect(parentRect, this.state0Texture.Bounds);
                spriteBatch.Draw(this.state0Texture, switchRect, null, Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, NextFrontIndex(globalZIndex, 2));
            }
            else
            {
                Rectangle switchRect            = this.CalcViewportRect(parentRect, this.state1Texture.Bounds);
                spriteBatch.Draw(this.state1Texture, switchRect, null, Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, NextFrontIndex(globalZIndex, 2));
            }
        }

        public override void InjectMouseEvent(MouseEvent evt, GameTime gt)
        {
            this.inputProcessor.InjectMouseEvent(evt, gt);
        }

        #endregion


        #region Event Handlers

        private void HandleInputProcessorSwipeEvent(object sender, VerticalSwipeProcessor.SwipeEventArgs e)
        {
            this.FireTriggerEvent(e);
        }

        #endregion


        #region Helpers

        private void FireTriggerEvent(VerticalSwipeProcessor.SwipeEventArgs args)
        {
            SwitchStates currentState   = this.converter.Convert(this.Value);
            float oldValue              = this.Value;
            if (args.Direction == this.nextStateDirection)
            {
                switch(currentState)
                {
                    case SwitchStates.State0: this.Value = this.converter.ConvertBack(SwitchStates.State1); break;
                }
            }
            else
            {
                switch(currentState)
                {
                    case SwitchStates.State1: this.Value = this.converter.ConvertBack(SwitchStates.State0); break;
                }
            }

            if (oldValue != this.Value)
            {
                this.TriggerEvent(this, new TriggerValueEventArgs(this.DataProperty, oldValue, this.Value));
            }
            else
            {
                Debug.Assert(false, "Trigger event didn't result in new gauge value. It seems no state change was triggered by a input event. Please check triggering code");
            }
        }

        #endregion

    }
}
